package pl.edu.agh.student.vrp;

import java.io.BufferedWriter;
import java.io.IOException;
import org.jgap.Gene;
import org.jgap.IChromosome;
import org.jgap.impl.IntegerGene;
import pl.edu.agh.student.vrp.utils.ChromosomeUtils;

/**
 *
 * @author janburkot
 */
public class PrintUtils
{

    private GA vrp;

    public PrintUtils(GA ga)
    {
        this.vrp = ga;
    }

    public void print(IChromosome a_subject, BufferedWriter outputWriter) throws IOException {
        double b_vi = 0.0D; //poczatek obslugi klienta vi

        double Q = 0.0D; //suma ilosci towarow
        double C = 0.0D; //suma kosztow przejazdu
        
        double B = 0.0D;
        double m = 1;
        double M = 0;
        double W = 0;
        double S = 0;
        
        int tv= vrp.getTotalVehicles();
        int nod= vrp.getDestinations().size();
        for (Gene[] route : ChromosomeUtils.getRoutes(a_subject, tv, nod))
        {
            System.out.println("=================================");
            M += m;
            //brak polaczenia baza klient
            //jednostkowy kosz przejazdu z 0 to i
            double c_i = distance( 0
                    ,  ((IntegerGene) route[0]).intValue());//route.length - 1
            
            //jednostkowa ilosc towaru dla 1
            double q_i = vrp.getDestinations().get(((IntegerGene) route[0]).intValue()).getDemand();
            
            C += c_i;
            Q = q_i;
            
            //poczatek okan czasowego dla 0
            double e_vi = vrp.getDestinations().get(((IntegerGene) route[0]).intValue()).getReadyTime();
            
            double b_v_j = vrp.getDestinations().get(0).getReadyTime();
            double delta_v_j = vrp.getDestinations().get(0).getServiceTime();
            double c_v_j = c_i;
            
            //System.out.println("B_vi: "+b_vi);
            //poczatek obslugi i
            b_vi =Math.max(e_vi, b_v_j + delta_v_j + c_v_j);
            
            double w_v_i = Math.max(0, b_vi - b_v_j - delta_v_j - c_v_j);
            W += w_v_i;
            
            int cid = ((IntegerGene) route[0]).intValue();
            double delta_v_i = vrp.getDestinations().get(cid).getServiceTime();
            if (!checkTimeWindow(b_vi, cid) ) {
                //niezmiescilismy sie w oknie
                double dueDate = vrp.getDestinations().get(cid).getDueTime();
                    
                B += 1 * (b_vi - dueDate);
            }
            
            System.out.println("K: "+((IntegerGene) route[0]).intValue());
            for (int i = 0; i < route.length - 1; ++i)
            {
                IntegerGene geneA = (IntegerGene) route[i]; //from
                IntegerGene geneB = (IntegerGene) route[(i + 1)]; //to
                int a = geneA.intValue();
                int b = geneB.intValue();
                
                int customerId = ((IntegerGene) route[i+1]).intValue();
                int prevCustomerId = ((IntegerGene) route[i]).intValue();
                
                //jednostkowy kosz przejazdu z i-1 to i
                c_i = distance(a, b);
                C += c_i;
                
                q_i = vrp.getDestinations().get(customerId).getDemand();
                Q+= q_i;
                
                //poczatek obslugi i-1
                b_v_j = b_vi;
                
                //czas obslugi i-1
                delta_v_j = vrp.getDestinations().get(prevCustomerId).getServiceTime();
                c_v_j = c_i;
                //poczatek okna czasowego dla i
                e_vi = vrp.getDestinations().get(customerId).getReadyTime();
                
                //noew
                b_vi =Math.max(e_vi, b_v_j + delta_v_j + c_v_j);
                //System.out.println("B_vi: "+b_vi);
                w_v_i = Math.max(0, b_vi - b_v_j - delta_v_j - c_v_j);
                W += w_v_i;
                
                System.out.println("K: "+((IntegerGene) route[i+1]).intValue());
                if (Q > vrp.getVehicleCapacity())
                {
                    System.out.println("Przekroczona pojemnosc samochodu");
                    System.out.println("Q: "+Q);
                    S += Q - vrp.getVehicleCapacity();
                    //System.out.println("Capacity: "+c);
                }
                
                //System.out.println("B_vi: "+b_vi);
                //System.out.println("W_vi: "+w_v_i);
                delta_v_i = vrp.getDestinations().get(customerId).getServiceTime();
                if(!checkTimeWindow(b_vi, customerId) ){
                    //return 0;
                    double dueDate = vrp.getDestinations().get(customerId).getDueTime();
                    B += (b_vi - dueDate);
                    System.out.println("Poza oknem: "+(b_vi - dueDate));
                }
            }
            
            c_i = distance(((IntegerGene) route[route.length - 1]).intValue()
                    ,  0);//route.length - 1
            C += c_i;
            
            b_v_j = b_vi;
            
            if(!(b_v_j + delta_v_j + c_v_j < vrp.getDestinations().get(0).getDueTime())){
                double dueDate = vrp.getDestinations().get(0).getDueTime();
                B += (b_vi - dueDate);
                b_vi = b_v_j + delta_v_j + c_v_j;
                System.out.println("Poza oknem: "+(b_vi - dueDate));
            }
            
            System.out.println("=================================");
            
        }

        System.out.println("C: "+C);
        System.out.println("M: "+M);
        System.out.println("B: "+B);
        System.out.println("W: "+W);
        System.out.println("S: "+S);

        outputWriter.write("C: "+C);
        outputWriter.newLine();
        outputWriter.write("M: "+M);
        outputWriter.newLine();
        outputWriter.write("B: "+B);
        outputWriter.newLine();
        outputWriter.write("W: "+W);
        outputWriter.newLine();
        outputWriter.write("S: "+S);
        outputWriter.newLine();

    }

    public double distance(Gene a_from, Gene a_to)
    {

        IntegerGene geneA = (IntegerGene) a_from;
        IntegerGene geneB = (IntegerGene) a_to;
        int a = geneA.intValue();
        int b = geneB.intValue();
        double x1 = vrp.getDestinations().get(a).getxCoordinate();
        double y1 = vrp.getDestinations().get(a).getyCoorginate();
        double x2 = vrp.getDestinations().get(b).getxCoordinate();
        double y2 = vrp.getDestinations().get(b).getyCoorginate();

        return Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));

    }
    
    public double distance(int a, int b)
    {
        double x1 = vrp.getDestinations().get(a).getxCoordinate();
        double y1 = vrp.getDestinations().get(a).getyCoorginate();
        double x2 = vrp.getDestinations().get(b).getxCoordinate();
        double y2 = vrp.getDestinations().get(b).getyCoorginate();

        return Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));

    }

    protected boolean checkTimeWindow(double time, int customerId){
        //jak wogole policzyc czas przejazdu
        
        double readyTime = vrp.getDestinations().get(customerId).getReadyTime();
        double dueDate = vrp.getDestinations().get(customerId).getDueTime();
        
        if(time >= readyTime && time <= dueDate){ //e_vi <= b_vi <= l_vi 
            return true;
        }  
        
        return false;
    }
    
}
